"""
增强版 LLM 模块
支持 Open Interpreter 风格的自然语言指令解析
"""

import json
import re
from typing import Any, Dict, List, Optional

from .llm import DoubaoLLM
from .logger import log_event


class EnhancedDoubaoLLM(DoubaoLLM):
    """
    增强版豆包LLM
    在原有功能基础上，增加对 Open Interpreter 风格计算机控制指令的解析能力
    """
    
    def __init__(self, api_key: Optional[str] = None, api_url: Optional[str] = None, model: Optional[str] = None):
        super().__init__(api_key, api_url, model)
        self.computer_action_templates = self._load_computer_action_templates()

    def _load_computer_action_templates(self) -> Dict[str, Any]:
        """加载计算机操作的动作模板"""
        return {
            "screenshot_patterns": [
                r"截图|截屏|保存屏幕|screen.*shot",
                r"拍照|拍屏幕",
            ],
            "click_text_patterns": [
                r"点击.*?[\"'](.*?)[\"']",
                r"点击.*?文字.*?[\"'](.*?)[\"']",
                r"点击.*?按钮.*?[\"'](.*?)[\"']",
                r"点击.*?链接.*?[\"'](.*?)[\"']",
            ],
            "type_text_patterns": [
                r"输入.*?[\"'](.*?)[\"']",
                r"打字.*?[\"'](.*?)[\"']",
                r"键入.*?[\"'](.*?)[\"']",
                # 放宽：不带引号的匹配，避免包含引号；到动作边界/标点/结束
                r"输入[，,:\s]*([^\n“”\"']+?)(?=然后|并且|并|接着|随后|接下来|关闭|点击|搜索|查找|激活|切换|按|组合键|快捷键|滚动|上滑|下滑|$|[，,。……\.])",
            ],
            "key_press_patterns": [
                r"按.*?键.*?(enter|回车|空格|space|tab|制表|esc|escape)",
                r"按.*?(f\d+|ctrl|alt|shift|win|windows)",
            ],
            "hotkey_patterns": [
                r"按.*?(ctrl|alt|shift|win).*?\+.*?([\w\d]+)",
                r"快捷键.*?(ctrl|alt|shift|win).*?\+.*?([\w\d]+)",
                r"组合键.*?(ctrl|alt|shift|win).*?\+.*?([\w\d]+)",
            ],
            "scroll_patterns": [
                r"滚动|滑动|翻页",
                r"向上.*?滚|向下.*?滚",
                r"上滑|下滑",
            ],
            "window_patterns": [
                r"打开.*?窗口.*?[\"'](.*?)[\"']",
                r"激活.*?窗口.*?[\"'](.*?)[\"']",
                r"切换.*?到.*?[\"'](.*?)[\"']",
                r"找到.*?窗口.*?[\"'](.*?)[\"']",
            ],
            "wait_patterns": [
                r"等待.*?[\"'](.*?)[\"'].*?出现",
                r"等待.*?看到.*?[\"'](.*?)[\"']",
                r"等.*?[\"'](.*?)[\"'].*?显示",
            ],
        }

    def parse_command(self, text: str) -> List[Dict[str, Any]]:
        """
        解析自然语言指令，支持原有功能 + Open Interpreter 风格的计算机控制
        """
        try:
            # 先尝试解析计算机控制指令（更符合本项目端到端验证需求）
            computer_actions = self._parse_computer_commands(text)
            if computer_actions:
                return computer_actions

            # 再使用原有解析逻辑作为兜底
            legacy_actions = super().parse_command(text)
            return legacy_actions if legacy_actions else [{"type": "unknown", "text": text}]
            
        except Exception as e:
            log_event("PARSE_COMMAND_ERROR", f"指令解析失败: {e}")
            return [{"type": "unknown", "text": text, "error": str(e)}]

    def _parse_computer_commands(self, text: str) -> List[Dict[str, Any]]:
        """解析计算机控制相关的指令"""
        actions: List[Dict[str, Any]] = []
        text_lower = text.lower()

        # 优先使用复杂指令解析，保证顺序（例如：先打开再输入）并避免重复
        complex_actions = self._parse_complex_commands(text)
        if complex_actions:
            return complex_actions

        # 截图指令
        if self._match_patterns(text_lower, self.computer_action_templates["screenshot_patterns"]):
            action = {"type": "computer_screenshot"}
            path_match = re.search(r"保存.*?到.*?[\"'](.*?)[\"']", text)
            if path_match:
                action["save_path"] = path_match.group(1)
            actions.append(action)

        # 点击文本指令
        click_matches = self._extract_patterns(text, self.computer_action_templates["click_text_patterns"])
        for match in click_matches:
            actions.append({"type": "computer_click_text", "text": match})

        # 输入文本指令（在非复杂指令场景下才解析）
        type_matches = self._extract_patterns(text, self.computer_action_templates["type_text_patterns"])
        for match in type_matches:
            actions.append({"type": "computer_type", "text": match.strip()})

        # 按键指令
        key_matches = self._extract_key_patterns(text)
        for key in key_matches:
            actions.append({"type": "computer_key", "key": key})

        # 组合键指令
        hotkey_matches = self._extract_hotkey_patterns(text)
        for keys in hotkey_matches:
            actions.append({"type": "computer_hotkey", "keys": keys})

        # 滚动指令
        if self._match_patterns(text_lower, self.computer_action_templates["scroll_patterns"]):
            clicks = 3
            if "向上" in text or "上滑" in text:
                clicks = -3
            scroll_match = re.search(r"滚动.*?(\d+)", text)
            if scroll_match:
                scroll_amount = int(scroll_match.group(1))
                clicks = scroll_amount if "向下" in text or "下滑" in text else -scroll_amount
            actions.append({"type": "computer_scroll", "clicks": clicks})

        # 窗口操作指令
        window_matches = self._extract_patterns(text, self.computer_action_templates["window_patterns"])
        for window_title in window_matches:
            operation = "activate"
            if "打开" in text:
                operation = "activate"
            elif "找到" in text or "查找" in text:
                operation = "find"
            actions.append({"type": "computer_window", "operation": operation, "title": window_title})

        # 等待指令
        wait_matches = self._extract_patterns(text, self.computer_action_templates["wait_patterns"])
        for wait_text in wait_matches:
            timeout = 10.0
            time_match = re.search(r"等待.*?(\d+).*?秒", text)
            if time_match:
                timeout = float(time_match.group(1))
            actions.append({"type": "computer_wait", "wait_type": "text", "text": wait_text, "timeout": timeout})

        return actions

    def _parse_complex_commands(self, text: str) -> List[Dict[str, Any]]:
        """解析复杂的复合指令"""
        actions: List[Dict[str, Any]] = []
        
        # 原有："打开X然后Y" 的解析
        app_operation_match = re.search(r"打开.*?([^，,。……\.]+).*?然后.*?([^，,。……\.]+)", text)
        if app_operation_match:
            app_name = app_operation_match.group(1).strip()
            operation = app_operation_match.group(2).strip()
            
            # 先打开应用
            actions.append({
                "type": "app_control",
                "app_name": app_name,
                "operation": "open"
            })
            
            # 执行后续操作（移除自动等待，减少对 OCR 的依赖）
            if "点击" in operation:
                click_match = re.search(r"点击.*?[\"'](.*?)[\"']", operation)
                if click_match:
                    actions.append({
                        "type": "computer_click_text",
                        "text": click_match.group(1)
                    })
            elif "输入" in operation:
                type_match = re.search(r"输入.*?[\"'](.*?)[\"']", operation)
                if type_match:
                    actions.append({
                        "type": "computer_type",
                        "text": type_match.group(1)
                    })
        
        # 新增：宽松解析 —— 独立提取 打开 / 输入 / 关闭
        # 打开（非贪婪，直到“然后/并且/并/接着/随后/接下来/动作边界/标点/结束”）
        open_match = re.search(r"打开\s*(.+?)(?=然后|并且|并|接着|随后|接下来|输入|打字|键入|关闭|点击|搜索|查找|激活|切换|按|组合键|快捷键|滚动|上滑|下滑|$|[，,。……\.])", text)
        app_open = open_match.group(1).strip() if open_match else None
        if app_open:
            actions.append({
                "type": "app_control",
                "app_name": app_open,
                "operation": "open"
            })
            # 移除自动等待（computer_wait），避免对 OCR 的依赖
        
        # 输入（优先匹配带引号；若无引号则使用宽松匹配）
        type_match = re.search(r"输入[“\"'](.*?)[”\"']", text)
        if not type_match:
            type_match = re.search(r"输入[，,:\s]*(.+?)(?=然后|并且|并|接着|随后|接下来|关闭|点击|搜索|查找|激活|切换|按|组合键|快捷键|滚动|上滑|下滑|$|[，,。……\.])", text)
        if type_match:
            actions.append({
                "type": "computer_type",
                "text": type_match.group(1).strip()
            })
        
        # 关闭（若未显式给出应用名，用打开的应用名兜底；非贪婪匹配）
        close_match = re.search(r"关闭\s*(.+?)(?=然后|并且|并|接着|随后|接下来|$|[，,。……\.])", text)
        app_close = close_match.group(1).strip() if close_match else None
        if ("关闭" in text) and (app_close or app_open):
            actions.append({
                "type": "app_control",
                "app_name": app_close or app_open,
                "operation": "close"
            })
        
        # 搜索并点击
        search_click_match = re.search(r"搜索.*?[\"'](.*?)[\"'].*?点击.*?[\"'](.*?)[\"']", text)
        if search_click_match:
            search_text = search_click_match.group(1)
            click_text = search_click_match.group(2)
            
            actions.extend([
                {"type": "computer_hotkey", "keys": ["ctrl", "f"]},  # 打开搜索
                {"type": "computer_type", "text": search_text},       # 输入搜索内容
                {"type": "computer_key", "key": "enter"},            # 确认搜索
                {"type": "computer_wait", "wait_type": "text", "text": click_text, "timeout": 5.0},  # 等待结果
                {"type": "computer_click_text", "text": click_text}   # 点击结果
            ])
        
        return actions

    def _match_patterns(self, text: str, patterns: List[str]) -> bool:
        """检查文本是否匹配任一模式"""
        for pattern in patterns:
            if re.search(pattern, text, re.IGNORECASE):
                return True
        return False
    
    def _extract_patterns(self, text: str, patterns: List[str]) -> List[str]:
        """从文本中提取匹配模式的内容"""
        matches = []
        for pattern in patterns:
            found = re.findall(pattern, text, re.IGNORECASE)
            matches.extend(found)
        return matches
    
    def _extract_key_patterns(self, text: str) -> List[str]:
        """提取按键指令"""
        keys = []
        key_mapping = {
            "回车": "enter", "enter": "enter",
            "空格": "space", "space": "space",
            "制表": "tab", "tab": "tab",
            "esc": "escape", "escape": "escape",
            "删除": "delete", "delete": "delete",
            "退格": "backspace", "backspace": "backspace",
        }
        
        for pattern in self.computer_action_templates["key_press_patterns"]:
            matches = re.findall(pattern, text, re.IGNORECASE)
            for match in matches:
                key = match.lower()
                mapped_key = key_mapping.get(key, key)
                if mapped_key not in keys:
                    keys.append(mapped_key)
        
        return keys
    
    def _extract_hotkey_patterns(self, text: str) -> List[str]:
        """提取组合键指令"""
        matches = re.findall(self.computer_action_templates["hotkey_patterns"][0], text, re.IGNORECASE)
        keys_list: List[List[str]] = []
        for mod, key in matches:
            keys_list.append([mod.lower(), key.lower()])
        return keys_list

    def generate_computer_plan(self, goal: str) -> List[Dict[str, Any]]:
        """
        使用LLM生成计算机操作计划
        这是一个更高级的功能，类似于 Open Interpreter 的规划能力
        """
        try:
            system_prompt = """你是一个计算机操作专家。用户会告诉你一个目标，你需要将其分解为具体的计算机操作步骤。

请将操作分解为以下类型的动作：
1. computer_screenshot - 截图
2. computer_click_text - 点击文本
3. computer_type - 输入文本
4. computer_key - 按键
5. computer_hotkey - 组合键
6. computer_scroll - 滚动
7. computer_window - 窗口操作
8. computer_wait - 等待
9. app_control - 应用控制

请以JSON格式返回操作步骤列表。每个步骤包含type和相关参数。

示例：
用户目标：打开记事本并输入"Hello World"
返回：
[
    {"type": "app_control", "app_name": "notepad", "operation": "open"},
    {"type": "computer_wait", "wait_type": "text", "text": "记事本", "timeout": 5.0},
    {"type": "computer_type", "text": "Hello World"}
]
"""
            
            messages = [
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": f"目标：{goal}"}
            ]
            
            response = self.chat(messages, response_json=True)
            
            try:
                plan = json.loads(response)
                if isinstance(plan, list):
                    return plan
            except Exception:
                pass
            
            return []
        except Exception as e:
            log_event("COMPUTER_PLAN_ERROR", f"生成计算机操作计划失败: {e}")
            return []

    def explain_computer_action(self, action: Dict[str, Any]) -> str:
        """解释计算机操作动作"""
        action_type = action.get("type", "")
        
        explanations = {
            "computer_screenshot": "截取屏幕截图",
            "computer_click_text": f"点击文本：{action.get('text', '')}",
            "computer_type": f"输入文本：{action.get('text', '')}",
            "computer_key": f"按键：{action.get('key', '')}",
            "computer_hotkey": f"组合键：{'+' .join(action.get('keys', []))}",
            "computer_scroll": f"滚动：{action.get('clicks', 0)}格",
            "computer_window": f"窗口操作：{action.get('operation', '')} {action.get('title', '')}",
            "computer_wait": f"等待：{action.get('text', '')}出现",
            "app_control": f"应用控制：{action.get('operation', '')} {action.get('app_name', '')}"
        }
        
        return explanations.get(action_type, f"未知操作：{action_type}")